From: Daniel van Vugt Date: Fri, 15 Sep 2017 09:49:12 +0000 (+0800) Subject: Fix irregular gdk_frame_clock_get_frame_time X-Git-Tag: archive/raspbian/3.24.39-1+rpi1~1^2~65^2~38^2~1 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=c6901a8b950f156aaddf2ee8f8fb39440b7b9cfd;p=gtk%2B3.0.git Fix irregular gdk_frame_clock_get_frame_time This fixes stuttering in animations that rely on the regularity of gdk_frame_clock_get_frame_time. https://bugzilla.gnome.org/show_bug.cgi?id=787665 BEFORE gdkgears: 58 FPS and visibly stuttering gnome-maps on a 59.95Hz monitor: "paint" g_get_monotonic_time +17278μs, gdk_frame_clock_get_frame_time +17278μs "paint" g_get_monotonic_time +17449μs, gdk_frame_clock_get_frame_time +17426μs "paint" g_get_monotonic_time +17620μs, gdk_frame_clock_get_frame_time +17600μs AFTER gdkgears: 60 FPS and smoother gnome-maps on a 59.95Hz monitor: "paint" g_get_monotonic_time +18228μs, gdk_frame_clock_get_frame_time +16680μs "paint" g_get_monotonic_time +15010μs, gdk_frame_clock_get_frame_time +16680μs "paint" g_get_monotonic_time +17134μs, gdk_frame_clock_get_frame_time +16680μs --- diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c index 12897f4236..a0ca0ca1b9 100644 --- a/gdk/gdkframeclockidle.c +++ b/gdk/gdkframeclockidle.c @@ -123,6 +123,7 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle) frame_clock_idle->priv = priv = gdk_frame_clock_idle_get_instance_private (frame_clock_idle); + priv->frame_time = g_get_monotonic_time (); /* more sane than zero */ priv->freeze_count = 0; } @@ -350,9 +351,37 @@ gdk_frame_clock_paint_idle (void *data) case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT: if (priv->freeze_count == 0) { - priv->frame_time = compute_frame_time (clock_idle); + gint64 frame_interval = FRAME_INTERVAL; + gint64 reset_frame_time; + gint64 smoothest_frame_time; + gint64 frame_time_error; + GdkFrameTimings *prev_timings = + gdk_frame_clock_get_current_timings (clock); + + if (prev_timings && prev_timings->refresh_interval) + frame_interval = prev_timings->refresh_interval; + + /* We are likely not getting precisely even callbacks in real + * time, particularly if the event loop is busy. + * This is a documented limitation in the precision of + * gdk_threads_add_timeout_full and g_timeout_add_full. + * + * In order to avoid this imprecision from compounding between + * frames and affecting visual smoothness, we correct frame_time + * to more precisely match the even refresh interval of the + * physical display. This also means we proactively avoid (most) + * missed frames before they occur. + */ + smoothest_frame_time = priv->frame_time + frame_interval; + reset_frame_time = compute_frame_time (clock_idle); + frame_time_error = ABS (reset_frame_time - smoothest_frame_time); + if (frame_time_error >= frame_interval) + priv->frame_time = reset_frame_time; + else + priv->frame_time = smoothest_frame_time; _gdk_frame_clock_begin_frame (clock); + /* Note "current" is different now so timings != prev_timings */ timings = gdk_frame_clock_get_current_timings (clock); timings->frame_time = priv->frame_time;